package com.wteam.dragon.system.apps.server.service.impl;

import cn.hutool.core.lang.Dict;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.qiniu.common.QiniuException;
import com.qiniu.http.Response;
import com.qiniu.storage.BucketManager;
import com.qiniu.storage.Configuration;
import com.qiniu.storage.UploadManager;
import com.qiniu.storage.model.DefaultPutRet;
import com.qiniu.util.Auth;
import com.wteam.dragon.system.apps.server.povo.bean.QiniuConfig;
import com.wteam.dragon.system.apps.server.povo.bean.QiniuContent;
import com.wteam.dragon.system.apps.server.mapper.QiniuConfigMapper;
import com.wteam.dragon.system.apps.server.mapper.QiniuContentMapper;
import com.wteam.dragon.system.apps.server.service.QiniuService;
import com.wteam.dragon.system.apps.server.util.QiNiuUtil;
import com.wteam.dragon.system.basebean.bean.ResultMessage;
import com.wteam.dragon.system.exception.BadRequestException;
import com.wteam.dragon.system.util.FileUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.util.List;
import java.util.Set;

/**
 * @Author 陈晓辉
 * @Date 2020/3/24
 */
@Service
@RequiredArgsConstructor
public class QiniuServiceImpl implements QiniuService {
    private final QiniuConfigMapper qiniuConfigMapper;
    private final QiniuContentMapper qiniuContentMapper;

    @Value("${qiniu.max-size}")
    private Long maxSize;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResultMessage addQiniuConfig(QiniuConfig qiniuConfig) {
        qiniuConfigMapper.insert(qiniuConfig);
        ResultMessage resultMessage = new ResultMessage();
        resultMessage.setStatus(HttpStatus.OK.value());
        resultMessage.setMessage("添加七牛云配置成功");
        return resultMessage;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResultMessage delQiniuConfig(Long id) {
        qiniuConfigMapper.deleteById(id);
        ResultMessage resultMessage = new ResultMessage();
        resultMessage.setStatus(HttpStatus.OK.value());
        resultMessage.setMessage("删除成功");
        return resultMessage;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResultMessage editQiniuConfig(QiniuConfig qiniuConfig) {
        qiniuConfigMapper.updateById(qiniuConfig);
        ResultMessage resultMessage = new ResultMessage();
        resultMessage.setStatus(HttpStatus.OK.value());
        resultMessage.setMessage("更新成功");
        return resultMessage;
    }

    @Override
    public ResultMessage listQiniuConfig() {
        QueryWrapper<QiniuConfig> qiniuConfigQueryWrapper = new QueryWrapper<>();
        List<QiniuConfig> qiniuConfigList = qiniuConfigMapper.selectList(qiniuConfigQueryWrapper);
        Dict resultMap = Dict.create()
                .set("message", "请求成功")
                .set("qiniuConfigList", qiniuConfigList);
        ResultMessage resultMessage = new ResultMessage();
        resultMessage.setStatus(HttpStatus.OK.value());
        resultMessage.setResultParam(resultMap);
        return resultMessage;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResultMessage uploadFile(MultipartFile file, QiniuConfig qiniuConfig) {
        FileUtil.checkSize(maxSize, file.getSize());
        if(qiniuConfig.getId() == null){
            throw new BadRequestException("请先添加相应配置，再操作");
        }
        // 构造一个带指定Zone对象的配置类
        Configuration cfg = new Configuration(QiNiuUtil.getRegion(qiniuConfig.getZone()));
        UploadManager uploadManager = new UploadManager(cfg);
        Auth auth = Auth.create(qiniuConfig.getAccessKey(), qiniuConfig.getSecretKey());
        String upToken = auth.uploadToken(qiniuConfig.getBucket());

        String fileName = file.getOriginalFilename();

        QueryWrapper<QiniuContent> contentQueryWrapper = new QueryWrapper<>();
        contentQueryWrapper.lambda().eq(QiniuContent::getFileName, fileName);
        QiniuContent content = qiniuContentMapper.selectOne(contentQueryWrapper);
        if(content != null) {
            fileName = QiNiuUtil.getFileName(fileName);
        }
        Response response = null;
        try {
            response = uploadManager.put(file.getBytes(), fileName, upToken);
        } catch (IOException e) {
            e.printStackTrace();
        }
        //解析上传成功的结果
        DefaultPutRet putRet = null;
        try {
            putRet = JSON.parseObject(response.bodyString(), DefaultPutRet.class);
        } catch (QiniuException e) {
            e.printStackTrace();
            throw new BadRequestException("上传文件失败");
        }
        //存入数据库
        QiniuContent qiniuContent = new QiniuContent();
        qiniuContent.setSuffix(FileUtil.getExtensionName(putRet.key));
        qiniuContent.setBucket(qiniuConfig.getBucket());
        qiniuContent.setType(qiniuConfig.getType());
        qiniuContent.setFileName(FileUtil.getFileNameNoEx(putRet.key));
        qiniuContent.setUrl(qiniuConfig.getHost()+"/"+putRet.key);
        qiniuContent.setSize(FileUtil.getSize(Integer.parseInt(file.getSize()+"")));
        qiniuContentMapper.insert(qiniuContent);
        ResultMessage resultMessage = new ResultMessage();
        resultMessage.setStatus(HttpStatus.OK.value());
        resultMessage.setMessage("上传文件成功");
        return resultMessage;
    }

    @Override
    public ResultMessage downloadFile(QiniuConfig qiniuConfig, QiniuContent qiniuContent) {
        String finalUrl;
        String type = "公开";
        if(type.equals(qiniuContent.getType())){
            finalUrl  = qiniuContent.getUrl();
        } else {
            Auth auth = Auth.create(qiniuConfig.getAccessKey(), qiniuConfig.getSecretKey());
            // 1小时，可以自定义链接过期时间
            long expireInSeconds = 3600;
            finalUrl = auth.privateDownloadUrl(qiniuContent.getUrl(), expireInSeconds);
        }
        Dict resultMap = Dict.create()
                .set("message", "请求成功")
                .set("finalUrl",finalUrl);
        ResultMessage resultMessage = new ResultMessage();
        resultMessage.setStatus(HttpStatus.OK.value());
        resultMessage.setResultParam(resultMap);
        return resultMessage;
    }

    /**
     * 批量删除文件
     * @param qiniuConfig
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResultMessage delFile(QiniuConfig qiniuConfig, Set<Long> qiniuContentIds) {
        //构造一个带指定Zone对象的配置类
        Configuration cfg = new Configuration(QiNiuUtil.getRegion(qiniuConfig.getZone()));
        Auth auth = Auth.create(qiniuConfig.getAccessKey(), qiniuConfig.getSecretKey());
        BucketManager bucketManager = new BucketManager(auth, cfg);
        try {
            for (Long qiniuContentId : qiniuContentIds){
                QiniuContent qiniuContent = qiniuContentMapper.selectById(qiniuContentId);
                bucketManager.delete(qiniuContent.getBucket(), qiniuContent.getFileName() + "." + qiniuContent.getSuffix());
            }
            qiniuContentMapper.deleteBatchIds(qiniuContentIds);
        } catch (QiniuException ex) {
            qiniuContentMapper.deleteBatchIds(qiniuContentIds);
        }
        ResultMessage resultMessage = new ResultMessage();
        resultMessage.setStatus(HttpStatus.OK.value());
        resultMessage.setMessage("删除成功");
        return resultMessage;
    }

    @Override
    public ResultMessage pageQiniuContent(Page<QiniuContent> page) {
         QueryWrapper<QiniuContent> queryWrapper = new QueryWrapper<>();
         queryWrapper.lambda().orderByAsc(QiniuContent::getCreateTime);
         Page<QiniuContent> qiniuContentPage = qiniuContentMapper.selectPage(page, queryWrapper);
         Dict resultMap = Dict.create()
                 .set("message", "请求成功")
                 .set("qiniuContentList",qiniuContentPage);
        ResultMessage resultMessage = new ResultMessage();
         resultMessage.setStatus(HttpStatus.OK.value());
         resultMessage.setResultParam(resultMap);
        return resultMessage;
    }
}
